Skip to content

feat: Add vault-fetcher CLI tool (Phase 2)#380

Draft
Alan-Cha wants to merge 1 commit into
feat/vault-integrationfrom
feat/vault-fetcher-cli
Draft

feat: Add vault-fetcher CLI tool (Phase 2)#380
Alan-Cha wants to merge 1 commit into
feat/vault-integrationfrom
feat/vault-fetcher-cli

Conversation

@Alan-Cha

@Alan-Cha Alan-Cha commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

Phase 2 of the Vault pattern: vault-fetcher CLI tool for fetching secrets from Vault at pod startup.

Stacked on: #379 (Phase 1 - authlib/vault library)

This PR builds the init container that uses the authlib/vault library to fetch secrets and write them to files.

What This Adds

vault-fetcher CLI Tool

A standalone binary that runs as an init container:

  1. Reads configuration (which secrets to fetch)
  2. Authenticates to Vault using SPIFFE JWT-SVID
  3. Fetches secrets using authlib/vault
  4. Writes secrets to files with secure permissions
  5. Exits (application container starts)

Features

  • Uses authlib/vault — All Vault operations via Phase 1 library
  • Multiple auth methods — JWT (SPIFFE), Kubernetes SA, token
  • Batch fetching — Fetch multiple secrets in one run
  • Flexible output — Individual files, env file, JSON
  • Secure by default — File mode 0600, runs as non-root (UID 65532)
  • Retry logic — 3 auth attempts with exponential backoff
  • Env var overrides — VAULT_ADDR, VAULT_ROLE, etc.
  • Fail-fast — Clear errors, non-zero exit codes

Files Added

  • `vault-fetcher/main.go` (330 lines) — CLI implementation
  • `vault-fetcher/Dockerfile` — Multi-stage distroless image (~20MB)
  • `vault-fetcher/README.md` (450+ lines) — Complete documentation
  • `vault-fetcher/config.yaml.example` — Example configuration
  • `vault-fetcher/go.mod`, `go.sum` — Go module
  • `go.work` — Updated workspace

Total: ~916 lines added

Usage Example

Configuration

```yaml

/etc/vault-fetcher/config.yaml

vault:
address: "https://vault.example.com"
auth_method: "jwt"
role: "github-agent-role"

secrets:

  • path: "secret/data/github/token"
    field: "token"
    output: "/shared/secrets/github-token"
    mode: "0600"
    ```

Deployment

```yaml
apiVersion: v1
kind: Pod
spec:
initContainers:

  • name: vault-fetcher
    image: ghcr.io/kagenti/kagenti-extensions/vault-fetcher:latest
    args:
    • --config=/etc/vault-fetcher/config.yaml
      volumeMounts:
    • name: spiffe-svid
      mountPath: /opt
    • name: shared-secrets
      mountPath: /shared/secrets
    • name: vault-fetcher-config
      mountPath: /etc/vault-fetcher

containers:

  • name: app
    volumeMounts:
    • name: shared-secrets
      mountPath: /shared/secrets
      readOnly: true

    App reads /shared/secrets/github-token

```

Output

```bash
[vault-fetcher] Starting vault-fetcher v0.1.0
[vault-fetcher] Loaded config from /etc/vault-fetcher/config.yaml
[vault-fetcher] Created Vault client (address=https://vault.example.com, auth_method=jwt)
[vault-fetcher] Successfully authenticated to Vault
[vault-fetcher] [1/1] Fetching secret: secret/data/github/token (field: token)
[vault-fetcher] [1/1] Secret fetched (lease: 3600s)
[vault-fetcher] [1/1] Written to: /shared/secrets/github-token
[vault-fetcher] All secrets fetched successfully
```

Testing

```bash
$ cd authbridge/vault-fetcher
$ go build -o vault-fetcher .
$ ./vault-fetcher --version
vault-fetcher version 0.1.0
```

Stacked PR Structure

```
main
└─> feat/vault-integration (PR #379) ← Phase 1: authlib/vault library
└─> feat/vault-fetcher-cli (THIS PR) ← Phase 2: vault-fetcher CLI
```

Merge order:

  1. Merge feat: Add Vault integration library to authlib #379 first (Phase 1 library)
  2. Then this PR will be updated to target `main`
  3. Then merge this PR (Phase 2 CLI)

Next Steps (Not in This PR)

  • Phase 3: Webhook integration (kagenti-operator)
  • Phase 4: Demo scenario, CI/CD pipeline

Review Notes

Key areas to review:

  1. Code quality: Is the CLI implementation clean and maintainable?
  2. Error handling: Are error messages clear and actionable?
  3. Configuration: Is the YAML schema intuitive?
  4. Security: File permissions, container security, secret handling
  5. Documentation: Is the README clear for users?

Questions for reviewers:

  • Should we add more validation in config loading?
  • Any concerns about the retry logic approach?
  • Should we support watching for config changes (vs one-shot)?

Assisted-By: Claude (Anthropic AI) noreply@anthropic.com

Implement standalone CLI tool for fetching secrets from Vault at pod startup.

This completes Phase 2 of the Vault pattern implementation. vault-fetcher
is an init container that:
- Authenticates to Vault using SPIFFE JWT-SVID (or K8s SA, or token)
- Fetches configured secrets from Vault
- Writes secrets to files with secure permissions
- Supports multiple output formats (individual files, env file, JSON)

Features:
- Uses authlib/vault library for all Vault operations
- Configuration via YAML file with env var overrides
- Retry logic for authentication (3 attempts with backoff)
- Fail-fast with clear error messages
- Minimal container image (distroless, ~20MB)
- Runs as non-root (UID 65532)

Files added:
- vault-fetcher/main.go (330 lines) — CLI implementation
- vault-fetcher/config.yaml.example — Example configuration
- vault-fetcher/Dockerfile — Multi-stage distroless image
- vault-fetcher/README.md (450+ lines) — Complete documentation
- vault-fetcher/go.mod, go.sum — Go module files
- go.work — Updated workspace to include vault-fetcher

Usage:
  vault-fetcher --config=/etc/vault-fetcher/config.yaml

Next steps (Phase 3):
- Webhook integration for automatic injection
- Demo scenario with real agent
- CI/CD pipeline for container image

Ref: #vault-pattern
Stacked on: #379

Signed-off-by: Alan Cha <Alan.cha1@ibm.com>
@Alan-Cha

Alan-Cha commented May 7, 2026

Copy link
Copy Markdown
Member Author

Closing to recreate as proper stacked PR using gh-stack

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. If this PR is still relevant, please comment or remove the stale label.

@github-actions github-actions Bot added the stale label Jul 7, 2026
@mrsabath

Copy link
Copy Markdown
Contributor

We are putting Vault activity on hold until we figure out whether this work should be done by CPEX or directly in Cortex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants